require "time"
require "cgi"
require "uri"
require "openssl"
require "digest/sha1"
require "bindings/image_collection"
require "bindings/index_request"
require "bindings/index_response"
require "bindings/search_request"
require "bindings/search_response"
require "bindings/error_response"
require 'net/https'
require 'base64'
require 'rexml/document'
include REXML


class Eyealike
  
  def initialize(access_id, secret_key, use_ssl=true, host_name="self.eyealike.com", port_number = 80)
    
    @access_id = access_id
    @secret_key = secret_key
    @use_ssl = use_ssl
    @host_name = host_name
    @port_number = port_number
  
  end

  
  def create_authorization_header(service_id, request_date, urls=nil, rois=nil,collection_ids=nil)
      
      msg = generate_signable_message(service_id, request_date, urls, rois, collection_ids)
      
      sig = create_signature(msg)
      
      return "EYEALIKE " + @access_id + " " + sig
    
  end
  
  def create_signature(msg)
    
    digest   = OpenSSL::Digest::Digest.new('sha1')
    hmac = OpenSSL::HMAC.digest(digest, @secret_key, msg)
    b64_hmac = Base64.encode64(hmac).chomp

    return b64_hmac
    
  end
  
  def generate_signable_message(service_id, request_date, urls=nil, rois=nil,collection_ids=nil)

    msg = ""
    msg.concat(@access_id)
    msg.concat("\n")
    msg.concat(service_id)
    msg.concat("\n")
    
    if (urls != nil)
       urls.each do |url|
        msg.concat(url)
        msg.concat("\n")
      end
    end
    
    if (rois != nil)
       rois.each do |roi|
        msg.concat(roi)
        msg.concat("\n")
      end
    end
    
    if (collection_ids != nil)
       collection_ids.each do |id|
        msg.concat(id)
        msg.concat("\n")
      end
    end
    
    msg.concat(request_date)
      
    return msg
    
  end
  

  def assemble_request_url(ep)
    
    url = "http"
    if @use_ssl == true
      url.concat("s")
    end
    url.concat("://")
    url.concat(@host_name)
    url.concat("/vsp/")
    url.concat(ep)
    
    return url
    
  end

  def create_request(method, endpoint, service_id, extraPathInfo = nil, urls = nil, rois = nil, collection_ids = nil)
    
     url = assemble_request_url(endpoint)
     if (extraPathInfo != nil)
       url.concat("/")
       url.concat(CGI::escape(extraPathInfo))
     end
         
     request_date = generate_request_date


     headers = {}
     headers['Date'] = request_date
     headers["Content-Type"] = "text/xml"
     headers['Authorization'] = create_authorization_header(service_id, request_date, urls, rois, collection_ids)
      
     request = Net::HTTP.const_get(method.to_s.capitalize).new(url, headers)

     return request
    
  end
  
  def instantiate_root_object(doc)
    
    tag_name = doc.root.name
    
    if (tag_name == 'image-collection')
      return ImageCollection.fromXml(doc)
    elsif (tag_name == 'index-response')
      return IndexResponse.fromXml(doc)
    elsif (tag_name == 'search-response')
      return SearchResponse.fromXml(doc)
    elsif (tag_name == 'error-response')
      return ErrorResponse.fromXml(doc)
    end
    
    
    
    
  end
  
  def compare(roiA, roiB)
    
    
    
  end
  
  def search(search_request)
    
    endpoint = "search"
    service_id = "similarity-search"
    
   
    request = create_request("POST", endpoint, service_id, nil, nil, search_request.roi_ids, [search_request.collection_id])
    
    response = execute_request(request, search_request)
    
    return response
    
  end
  
  def index_real_time(index_request)
    
    endpoint = "index"
    service_id = "similarity-single-index"
    
   
    request = create_request("POST", endpoint, service_id, nil, [index_request.url], nil, index_request.collection_id)
    
    response = execute_request(request, index_request)
    
    return response
    
  end
  
  def unindex(url)
    
    endpoint = "index"
    service_id = "similarity-remove-index"
    
    request = create_request("DELETE", endpoint, service_id, url, [url])
    
    response = execute_boolean_request(request)
    
    return response
    
    
  end
  
  def index_batch(request)
    
    endpoint = "index"
    service_id = "similarity-batch-index"
    
    
  end
  
  def check_batch_index_response()
    
    endpoint = "index"
    service_id = "similarity-batch-index-results"
    
    
  end
  
  def execute_request(request, payload)
    
     http = Net::HTTP.new(@host_name, @port_number)
     
     res =  http.request(request, payload.toXml())
      
     doc = Document.new(res.body)
     
     obj = instantiate_root_object(doc)
     
     return obj
     
  end
  
  def execute_boolean_request(request)
    
     http = Net::HTTP.new(@host_name, @port_number)
     
     res =  http.request(request)
    
     return res.body.eql? "OK"
     
  end

  def create_or_update_collection(collection)
    endpoint = "collection"
    service_id = "service-collection-manage"
    
    cIds = nil
    if (collection.collection_id != nil)
      cIds = [collection.collection_id]
    end
    
    request = create_request("PUT", endpoint, service_id, nil, nil, nil, cIds)
    
    response = execute_request(request, collection)
    
    return response
    
  end
  
  def generate_request_date
    
    now = Time.new()
    now = now.getutc
    return now.httpdate()
    
  end
  
  def delete_collection(collection_id)
    
    endpoint = "collection"
    service_id = "service-collection-delete"
    
    
    request = create_request("DELETE", endpoint, service_id, collection_id, nil, nil, [collection_id])
    
    response = execute_boolean_request(request)
    
    return response
    
  end
  

end